[id].vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. <template>
  2. <div class="admin--page-content">
  3. <div class="admin--form">
  4. <table class="admin--form--table">
  5. <colgroup>
  6. <col style="width: 140px;">
  7. <col>
  8. </colgroup>
  9. <tbody>
  10. <tr>
  11. <th><div>분야</div></th>
  12. <td>{{ data.field_name || "-" }}</td>
  13. </tr>
  14. <tr>
  15. <th><div>지역</div></th>
  16. <td>{{ data.area_name || "-" }}</td>
  17. </tr>
  18. <tr>
  19. <th><div>낚시터명</div></th>
  20. <td class="admin--table-title">{{ data.name || "-" }}</td>
  21. </tr>
  22. <tr>
  23. <th><div>운영시간</div></th>
  24. <td>{{ data.operating_hours || "-" }}</td>
  25. </tr>
  26. <tr>
  27. <th><div>주요 어종</div></th>
  28. <td>{{ data.fish_species || "-" }}</td>
  29. </tr>
  30. <tr>
  31. <th><div>우편번호</div></th>
  32. <td>{{ data.zip_code || "-" }}</td>
  33. </tr>
  34. <tr>
  35. <th><div>주소</div></th>
  36. <td>{{ data.address || "-" }}</td>
  37. </tr>
  38. <tr>
  39. <th><div>상세주소</div></th>
  40. <td>{{ data.address_detail || "-" }}</td>
  41. </tr>
  42. <tr>
  43. <th><div>참고항목</div></th>
  44. <td>{{ data.address_refer || "-" }}</td>
  45. </tr>
  46. <tr>
  47. <th><div>좌표</div></th>
  48. <td>
  49. <template v-if="data.lat && data.lng">{{ data.lat }}, {{ data.lng }}</template>
  50. <template v-else>-</template>
  51. </td>
  52. </tr>
  53. <tr>
  54. <th><div>사진</div></th>
  55. <td>
  56. <div v-if="data.photos && data.photos.length" class="onboard--photo-grid">
  57. <div v-for="p in data.photos" :key="p.id" class="onboard--photo-item">
  58. <img :src="getImageUrl(p.file_path)" :alt="p.original_name" />
  59. </div>
  60. </div>
  61. <template v-else>-</template>
  62. </td>
  63. </tr>
  64. <tr>
  65. <th><div>제휴 여부</div></th>
  66. <td>
  67. <span :class="['admin--badge', data.partnership_YN === 'Y' ? 'admin--badge-active' : 'admin--badge-ended']">
  68. {{ data.partnership_YN === "Y" ? "제휴" : "비제휴" }}
  69. </span>
  70. </td>
  71. </tr>
  72. <tr v-if="data.partnership_YN === 'Y'">
  73. <th><div>계좌번호</div></th>
  74. <td>
  75. <template v-if="data.account_number">
  76. {{ bankName(data.bank_code) }} {{ data.account_number }}<template v-if="data.account_holder"> ({{ data.account_holder }})</template>
  77. </template>
  78. <template v-else>-</template>
  79. </td>
  80. </tr>
  81. <tr>
  82. <th><div>상태</div></th>
  83. <td>
  84. <span :class="['admin--badge', data.status_YN === 'Y' ? 'admin--badge-active' : 'admin--badge-ended']">
  85. {{ data.status_YN === "Y" ? "사용중" : "미사용" }}
  86. </span>
  87. </td>
  88. </tr>
  89. <tr>
  90. <th><div>등록일</div></th>
  91. <td>{{ formatDateTime(data.created_at) }}</td>
  92. </tr>
  93. <tr>
  94. <th><div>최근 수정</div></th>
  95. <td>{{ formatDateTime(data.updated_at) }}</td>
  96. </tr>
  97. </tbody>
  98. </table>
  99. <!-- 버튼 영역 -->
  100. <div class="admin--form-actions">
  101. <button type="button" class="admin--btn" @click="goToList">
  102. ← 목록으로
  103. </button>
  104. <button type="button" class="admin--btn admin--btn-red-border ml--auto" @click="handleDelete">
  105. 삭제
  106. </button>
  107. <button type="button" class="admin--btn admin--btn-red" @click="goToEdit">
  108. 수정
  109. </button>
  110. </div>
  111. <!-- 알림 모달 -->
  112. <AdminAlertModal
  113. v-if="alertModal.show"
  114. :title="alertModal.title"
  115. :message="alertModal.message"
  116. :type="alertModal.type"
  117. @confirm="handleAlertConfirm"
  118. @cancel="handleAlertCancel"
  119. @close="closeAlertModal"
  120. />
  121. </div>
  122. </div>
  123. </template>
  124. <script setup>
  125. import { ref, onMounted } from "vue";
  126. import { useRoute, useRouter } from "vue-router";
  127. import AdminAlertModal from "~/components/admin/AdminAlertModal.vue";
  128. definePageMeta({
  129. layout: "admin",
  130. middleware: ["auth"],
  131. });
  132. const route = useRoute();
  133. const router = useRouter();
  134. const { get, del } = useApi();
  135. const { getImageUrl } = useImage();
  136. const fishingId = route.params.id;
  137. const data = ref({
  138. field_name: "",
  139. area_name: "",
  140. name: "",
  141. operating_hours: "",
  142. fish_species: "",
  143. zip_code: "",
  144. address: "",
  145. address_detail: "",
  146. address_refer: "",
  147. lat: "",
  148. lng: "",
  149. bank_code: "",
  150. account_number: "",
  151. account_holder: "",
  152. partnership_YN: "N",
  153. status_YN: "Y",
  154. created_at: "",
  155. updated_at: "",
  156. photos: [],
  157. });
  158. // 은행 코드 → 은행명
  159. const bankMap = {
  160. "002": "산업은행", "003": "기업은행", "004": "국민은행", "007": "수협은행",
  161. "011": "농협은행", "020": "우리은행", "023": "SC제일은행", "031": "대구은행",
  162. "032": "부산은행", "034": "광주은행", "035": "제주은행", "037": "전북은행",
  163. "039": "경남은행", "045": "새마을금고", "071": "우체국", "081": "하나은행",
  164. "088": "신한은행", "089": "케이뱅크", "090": "카카오뱅크", "092": "토스뱅크",
  165. };
  166. const bankName = (code) => bankMap[code] || (code ? code : "-");
  167. // 알림 모달
  168. const alertModal = ref({
  169. show: false,
  170. title: "알림",
  171. message: "",
  172. type: "alert",
  173. onConfirm: null,
  174. });
  175. const showAlert = (message, title = "알림") => {
  176. alertModal.value = { show: true, title, message, type: "alert", onConfirm: null };
  177. };
  178. const showConfirm = (message, onConfirm, title = "확인") => {
  179. alertModal.value = { show: true, title, message, type: "confirm", onConfirm };
  180. };
  181. const closeAlertModal = () => { alertModal.value.show = false; };
  182. const handleAlertConfirm = () => {
  183. if (alertModal.value.onConfirm) alertModal.value.onConfirm();
  184. closeAlertModal();
  185. };
  186. const handleAlertCancel = () => closeAlertModal();
  187. // 상세 조회
  188. const loadDetail = async () => {
  189. const { data: res, error } = await get(`/fishing/${fishingId}`);
  190. if (error || !res?.success) {
  191. showAlert(error?.message || res?.message || "조회에 실패했습니다.", "오류");
  192. return;
  193. }
  194. const row = res.data || {};
  195. data.value = {
  196. field_name: row.field_name ?? "",
  197. area_name: row.area_name ?? "",
  198. name: row.name ?? "",
  199. operating_hours: row.operating_hours ?? "",
  200. fish_species: row.fish_species ?? "",
  201. zip_code: row.zip_code ?? "",
  202. address: row.address ?? "",
  203. address_detail: row.address_detail ?? "",
  204. address_refer: row.address_refer ?? "",
  205. lat: row.lat ?? "",
  206. lng: row.lng ?? "",
  207. bank_code: row.bank_code ?? "",
  208. account_number: row.account_number ?? "",
  209. account_holder: row.account_holder ?? "",
  210. partnership_YN: row.partnership_YN ?? "N",
  211. status_YN: row.status_YN ?? "Y",
  212. created_at: row.created_at ?? "",
  213. updated_at: row.updated_at ?? "",
  214. photos: row.photos ?? [],
  215. };
  216. };
  217. // 삭제
  218. const handleDelete = () => {
  219. showConfirm(
  220. `'${data.value.name}' 낚시터를 삭제하시겠습니까?`,
  221. async () => {
  222. const { data: res, error } = await del(`/fishing/${fishingId}`);
  223. if (error || !res?.success) {
  224. showAlert(error?.message || res?.message || "삭제에 실패했습니다.", "오류");
  225. } else {
  226. showAlert(res.message || "삭제되었습니다.", "성공");
  227. setTimeout(() => router.push("/site-manager/fishing/list"), 800);
  228. }
  229. },
  230. "낚시터 삭제"
  231. );
  232. };
  233. // 이동
  234. const goToList = () => router.push("/site-manager/fishing/list");
  235. const goToEdit = () => router.push(`/site-manager/fishing/edit/${fishingId}`);
  236. // 일시 포맷
  237. const formatDateTime = (dateString) => {
  238. if (!dateString) return "-";
  239. const date = new Date(dateString.replace(" ", "T"));
  240. if (isNaN(date.getTime())) return dateString;
  241. return date.toLocaleString("ko-KR", {
  242. year: "numeric",
  243. month: "2-digit",
  244. day: "2-digit",
  245. hour: "2-digit",
  246. minute: "2-digit",
  247. });
  248. };
  249. onMounted(() => {
  250. loadDetail();
  251. });
  252. </script>